package com.wl.mall.service.search.service.impl;

import com.alibaba.fastjson.JSON;
import com.wl.mall.service.search.repository.SkuSearchMapper;
import com.wl.mall.service.search.service.SkuSearchService;
import com.wl.mall.search.entity.SkuEs;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;

@Service
public class SkuSearchServiceImpl implements SkuSearchService {

    @Autowired
    private SkuSearchMapper skuSearchMapper;

    @Resource
    private ElasticsearchRestTemplate elasticsearchRestTemplate;
    /***
     * 单个导入ES
     * @param skuEs
     */
    @Override
    public void add(SkuEs skuEs) {
        //属性转换
        String skuAttribute = skuEs.getSkuAttribute();
        if(!StringUtils.isEmpty(skuAttribute)){
            skuEs.setAttrMap(JSON.parseObject(skuAttribute, Map.class));
        }
        skuSearchMapper.save(skuEs);
    }

    /***
     * 根据ID删除
     * @param id
     */
    @Override
    public void del(String id) {
        skuSearchMapper.deleteById(id);
    }

    /***
     * 商品搜索
     * @param searchMap
     * @return
     */
    @Override
    public Map<String, Object> search(Map<String, Object> searchMap) {
        //条件封装
        NativeSearchQueryBuilder queryBuilder = queryBuilder(searchMap);

        //高亮配置
        HighlightBuilder.Field field = new HighlightBuilder.
                Field("name").                      //指定的高亮域
                preTags("<span style=\"color:red\">").   //前缀
                postTags("</span>").                      //后缀
                fragmentSize(100);
//添加高亮域
        queryBuilder.withHighlightFields(field);

        //分组实现-品牌，分类，属性
        group(queryBuilder,searchMap);


        //执行搜索
        AggregatedPage<SkuEs> result = elasticsearchRestTemplate.queryForPage(queryBuilder.build(),SkuEs.class,new HighlightResultMapper());

        //分组数据
        Map<String, Object> stringObjectMap = parseGroup(result.getAggregations());

        attrParse(stringObjectMap);
        //结果集
        List<SkuEs> list = result.getContent();
        //中记录数
        long totalElements = result.getTotalElements();

        Map<String,Object> resultMap = new HashMap<String,Object>();
        resultMap.put("list",list);
        resultMap.put("totalElements",totalElements);
        resultMap.putAll(stringObjectMap);
        return resultMap;
    }

    /***
     * 搜索条件组装
     */
    public NativeSearchQueryBuilder queryBuilder(Map<String,Object> searchMap){
        //QueryBuilder构建
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();

        //多条件组合查询对象
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();

        //条件判断
        if(searchMap!=null && searchMap.size()>0){
            //关键词
            Object keywords =searchMap.get("keywords");
            if(Objects.nonNull(keywords)){
                boolQuery.must(QueryBuilders.matchQuery("name",keywords.toString()));
            }

            //分类
            Object category =searchMap.get("category");
            if(Objects.nonNull(category)){
                boolQuery.must(QueryBuilders.termQuery("categoryName",category.toString()));
            }

            //品牌
            Object brand =searchMap.get("brand");
            if(Objects.nonNull(brand)){
                boolQuery.must(QueryBuilders.termQuery("brandName",brand.toString()));
            }

            //价格
            Object price =searchMap.get("price");
            if(Objects.nonNull(price)){
                //去掉元和以上，并按-分割
                String[] prices = price.toString()
                        .replace("元","")
                        .replace("以上","")
                        .split("-");
                //price>x
                boolQuery.must(QueryBuilders.rangeQuery("price").gt(Integer.valueOf(prices[0])));
                //price<=y
                if(prices.length==2){
                    boolQuery.must(QueryBuilders.rangeQuery("price").lte(Integer.valueOf(prices[1])));
                }
            }

            //属性查询
            for (Map.Entry<String, Object> entry : searchMap.entrySet()) {
                if(entry.getKey().startsWith("attr_")){
                    //获取结果
                    String key = entry.getKey().replaceFirst("attr_","");
                    String value = entry.getValue().toString();
                    //执行查询
                    boolQuery.must(QueryBuilders.termQuery("attrMap."+key+".keyword",value));
                }
            }
        }
        queryBuilder.withPageable(PageRequest.of(currentPage(searchMap),2));

        //排序
        Object sfield = searchMap.get("sfield");
        Object sm = searchMap.get("sm");
        if(Objects.nonNull(sfield) && Objects.nonNull(sm)){
            queryBuilder.withSort(
                    SortBuilders.fieldSort(sfield.toString())   //排序域
                            .order(SortOrder.valueOf(sm.toString())));  //排序方式
        }
        return queryBuilder.withQuery(boolQuery);
    }

    /***
     * 当前页
     */
    public int currentPage(Map<String,Object> searchMap){
        try {
            Object currentPage = searchMap.get("page");
            return Objects.nonNull(currentPage) && Integer.valueOf(currentPage.toString())>0? Integer.valueOf(currentPage.toString())-1:0;
        } catch (NumberFormatException e) {
            return 0;
        }
    }

    /***
     * 分组搜索
     */
    public void group(NativeSearchQueryBuilder builder,Map<String,Object> searchMap){
        //前端没有传入分类参数的时候查询分类集合作为搜索条件
        if(Objects.isNull(searchMap.get("category"))){
            //分类分组
            builder.addAggregation(AggregationBuilders
                    .terms("categoryList")  //查询的数据对应别名
                    .field("categoryName")         //根据categoryName分组
                    .size(100));                    //分组查询100条
        }
        //前端没有传入品牌参数的时候查询品牌集合作为搜索条件
        if(Objects.isNull(searchMap.get("brand"))){
            //品牌分组
            builder.addAggregation(AggregationBuilders
                    .terms("brandList")     //查询的数据对应别名
                    .field("brandName")            //根据brandName分组
                    .size(100));                    //分组查询100条
        }

//        //属性分组查询
//        builder.addAggregation(AggregationBuilders
//                .terms("attrmaps")      //查询的数据对应别名
//                .field("skuAttribute")         //根据brandName分组
//                .size(100000));                 //分组查询100000条
    }

    /****
     * 取出所有分组数据
     * @param aggregations
     * @return
     */
    public Map<String,Object> parseGroup(Aggregations aggregations) {
        //所有分组数据
        Map<String,Object> groups = new HashMap<String,Object>();
        for (Aggregation aggregation : aggregations) {
            //强转成ParsedStringTerms
            ParsedStringTerms pst= (ParsedStringTerms) aggregation;

            //定义一个集合存储
            List<String> values = new ArrayList<String>();
            for (Terms.Bucket bucket : pst.getBuckets()) {
                //单个对象值
                values.add(bucket.getKeyAsString());
            }
            //存入到Map中
            groups.put(pst.getName(),values);
        }
        return groups;
    }

    /****
     * 属性解析
     */
    public void attrParse(Map<String,Object> groupMap){
        //获取属性分组数据
        Object attrgroup = groupMap.get("attrmaps");
        if(attrgroup!=null){
            //强转成List
            List<String> groupList = (List<String>) attrgroup;

            //所有属性名拥有的属性集合
            Map<String,Set<String>> allMaps = new HashMap<String,Set<String>>();

            for (String attr : groupList) {
                //将当前attr解析成Map
                Map<String,String> attrMap = JSON.parseObject(attr,Map.class);

                for (Map.Entry<String, String> entry : attrMap.entrySet()) {
                    //判断allMaps中是否存在当前attr的属性,不存在则添加一个
                    Set<String> values = allMaps.get(entry.getKey());
                    if(values==null){
                        values=new HashSet<String>();
                    }
                    //存在，则取出来，再添加当前值
                    values.add(entry.getValue());
                    //将修改后的值添加到allMaps中
                    allMaps.put(entry.getKey(),values);
                }
            }

            //重置groupMap的值
            groupMap.put("attrmaps",allMaps);
        }
    }

}